package com.weaver.qfengx.api.ec;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import com.weaver.qfengx.DaoUtils;
import com.weaver.qfengx.LogUtils;
import com.weaver.qfengx.RequestUtils;
import com.weaver.qfengx.StringUtils;
import com.weaver.qfengx.config.DevModeConfig;
import okhttp3.OkHttpClient;
import okhttp3.Response;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author: Qfengx <qffg1998@126.com>
 * @Date: 2021-10-01 10:48
 */
// TODO 增加token失效重试
public class EcApiService {

    private static final LogUtils log = new LogUtils(EcApiService.class);
    private static OkHttpClient client = new OkHttpClient();

    static {
        // 设置client 拦截器，增加token重试机制
    }

    // 简单的内存定时缓存
    private static Cache<String, String> cache = CacheBuilder.newBuilder()
            .maximumSize(1)
            .expireAfterWrite(Long.parseLong(DevModeConfig.getPropConfig("apiservice.ec,token.expiresTime", "20").getValue()), TimeUnit.MINUTES)
            .build();

    private String host = "";
    private String publicKey = "";
    private String privateKey = "";
    private String spk = ""; // 注册成功返回的，其实就是注册的publicKey
    private String secret = ""; // 注册成功返回的
    private String appid = "";

    public EcApiService(String appid) {
        this("http://localhost", appid);
    }

    public EcApiService(String host, String appid) {
        this.appid = appid;
        this.host = host;
        loadKey();
    }

    public String getToken() throws ExecutionException {
        // 因为cache是多个实例对象共用的，所以要用host+appid进行前缀控制
        return cache.get(host + "-" + appid + "-" + "ec.token", () -> {
            // 公钥加密,所以RSA对象私钥为null
            RSA rsa = new RSA(null, spk);
            //对秘钥进行加密传输，防止篡改数据
            String encryptSecret = rsa.encryptBase64(secret, CharsetUtil.CHARSET_UTF_8, KeyType.PublicKey);
            try {
                //调用ECOLOGY系统接口进行注册
                String data = HttpRequest.post(host + "/api/ec/dev/auth/applytoken")
                        .header("appid", appid)
                        .header("secret", encryptSecret)
                        .header("time", "3600")
                        .execute().body();
                log.writeLog("getToken data => " + data);
                JSONObject res = JSONObject.parseObject(data);
                if (res.getInteger("code") == 0) {
                    return res.getString("token");
                } else {
                    throw new RuntimeException("token 获取失败：" + res.getString("msg"));
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("token 获取异常：" + e.getMessage());
            }
        });
    }

    private void register() {
        RSA rsa = new RSA();
        this.publicKey = rsa.getPublicKeyBase64();
        this.privateKey = rsa.getPrivateKeyBase64();
        log.writeLog("注册appid, publicKey => " + publicKey + ", privateKey => " + privateKey);
        //调用ECOLOGY系统接口进行注册
        try {
            String data = HttpRequest.post(host + "/api/ec/dev/auth/regist")
                    .header("appid", appid)
                    .header("cpk", publicKey)
                    .timeout(2000)
                    .execute().body();
            log.writeLog("注册结果 => " + data);
            JSONObject res = JSONObject.parseObject(data);
            if (res.getInteger("code") == 0) { // 成功
                secret = res.getString("secrit");
                spk = res.getString("spk");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.writeLog("注册失败");
        }
    }

    private void loadKey() { // 加载注册的密钥信息
        // 查询数据库中是否已经存在
        Map<String, String> appInfo = DaoUtils.executeQueryToMap("select * from ecology_biz_ec where appid = ?", appid);
        if (appInfo == null || appInfo.isEmpty()) { // 数据库中不存在注册信息
            log.writeLog("appid => " + appid + ", 数据库（ecology_biz_ec）中不存在");
            throw new RuntimeException("appid => " + appid + ", 数据库（ecology_biz_ec）中不存在");
        } else {
            String rsa_pub = appInfo.get("rsa_pub");
            String rsa_prv = appInfo.get("rsa_prv");
            String secrit = appInfo.get("secrit");
            String server_public_key = appInfo.get("server_public_key");
            if (StringUtils.isEmpty(rsa_pub) || StringUtils.isEmpty(rsa_prv) || StringUtils.isEmpty(secrit) || StringUtils.isEmpty(server_public_key)) {
                register();
            } else {
                this.publicKey = rsa_pub;
                this.privateKey = rsa_prv;
                this.secret = secrit;
                this.spk = server_public_key;
            }
        }
    }

    public Response requestApiGet(String apiAddress, String userid, Map<String, String> formData) throws IOException, ExecutionException {
        return requestApiGet(apiAddress, userid, Maps.newHashMap(), formData);
    }

    public Response requestApiGet(String apiAddress, Map<String, String> formData) throws IOException, ExecutionException {
        return requestApiGet(apiAddress, Maps.newHashMap(), formData);
    }

    public Response requestApiGet(String apiAddress, String userid) throws IOException, ExecutionException {
        return requestApiGet(apiAddress, userid, Maps.newHashMap());
    }

    /**
     * 默认以管理员的身份进行请求
     */
    public Response requestApiGet(String apiAddress, Map<String, String> headerData, Map<String, String> formData) throws IOException, ExecutionException {
        return requestApiGet(apiAddress, "1", headerData, formData);
    }

    public Response requestApiGet(String apiAddress, String userid,
                                  Map<String, String> headerData, Map<String, String> formData) throws ExecutionException, IOException {
        RSA rsa = new RSA(null, spk);
        String encryptUserid = rsa.encryptBase64(userid,CharsetUtil.CHARSET_UTF_8,KeyType.PublicKey);

        headerData.put("appid", appid);
        headerData.put("token", getToken());
        headerData.put("userid", encryptUserid);
        // 添加人员信息
        return RequestUtils.doGet(client,host + apiAddress, headerData, formData);
    }


    public Response requestApiSkipSessionGet(String apiAddress,
                                  Map<String, String> headerData, Map<String, String> formData) throws ExecutionException, IOException {
        headerData.put("appid", appid);
        headerData.put("token", getToken());
        headerData.put("skipsession", "1");
        // 添加人员信息
        return RequestUtils.doGetWithoutChange(client,host + apiAddress, headerData, formData);
    }

    public Response requestApiPost(String apiAddress, String userid, Map<String, String> formData) throws IOException, ExecutionException {
        return requestApiPost(apiAddress, userid, Maps.newHashMap(), formData);
    }

    public Response requestApiPost(String apiAddress, String userid) throws IOException, ExecutionException {
        return requestApiPost(apiAddress, userid, Maps.newHashMap());
    }

    public Response requestApiPost(String apiAddress, Map<String, String> formData) throws IOException, ExecutionException {
        return requestApiPost(apiAddress, Maps.newHashMap(), formData);
    }

    /**
     * 默认以管理员的身份进行请求
     */
    public Response requestApiPost(String apiAddress, Map<String, String> headerData, Map<String, String> formData) throws IOException, ExecutionException {
        return requestApiPost(apiAddress, "1", headerData, formData);
    }

    public Response requestApiPost(String apiAddress, String userid,
                                   Map<String, String> headerData, Map<String, String> formData) throws ExecutionException, IOException {
        RSA rsa = new RSA(null, spk);
        String encryptUserid = rsa.encryptBase64(userid,CharsetUtil.CHARSET_UTF_8,KeyType.PublicKey);

        headerData.put("appid", appid);
        headerData.put("token", getToken());
        headerData.put("userid", encryptUserid);
        // 添加人员信息
        return RequestUtils.doPost(client, host + apiAddress, headerData, formData);
    }

    public Response requestApiSkipSessionPost(String apiAddress, String userid,
                                   Map<String, String> headerData, Map<String, String> formData) throws ExecutionException, IOException {
        RSA rsa = new RSA(null, spk);

        headerData.put("appid", appid);
        headerData.put("token", getToken());
        headerData.put("skipsession", "1");
        // 添加人员信息
        return RequestUtils.doPost(client,host + apiAddress, headerData, formData);
    }

    public static void main(String[] args) {
        EcApiService apiService = new EcApiService("http://localhost:8082", "EEAA5436-7577-4BE0-8C6C-89E9D88805EB");
    }
}
